import { ConfigModule, ConfigService } from '@nestjs/config';
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import * as path from 'path';
import { getMetadataArgsStorage, DataSource } from 'typeorm';
import { addTransactionalDataSource } from 'typeorm-transactional';
import { RedisModule, RedisClientOptions } from '@liaoliaots/nestjs-redis';
import { LoggerModule } from '@/common/logger/logger.module';
import { RedisNamespace } from '@/common/config/config.interface';
import { SnakeNamingStrategy } from 'typeorm-naming-strategies';
import { CarouselModule } from '@/module/carousel/carousel.module';
import { FileModule } from '@/module/file/file.module';
import { HttpClientModule } from '@/common/http-client/http-client.module';
import { ScheduleModule } from '@nestjs/schedule';
import { ResourceModule } from '@/module/resource/resource.module';
import { RoleModule } from '@/module/role/role.module';
import { AdminModule } from '@/module/admin/admin.module';
import { UserModule } from '@/module/user/user.module';
import { ArticleModule } from '@/module/article/article.module';
import { VcodeModule } from '@/module/vcode/vcode.module';
import { EvaluationModule } from '@/module/evaluation/evaluation.module';
import { EvaluationDataModule } from '@/module/evaluation-data/evaluation-data.module';
import { EvaluationProjectModule } from '@/module/evaluation-project/evaluation-project.module';
import { GlobalConfigModule } from '@/module/global-config/global-config.module';
import { BrandModule } from '@/module/brand/brand.module';
import { SpecificationModule } from '@/module/specification/specification.module';
import { EvaluationSpecificationModule } from '@/module/evaluation-specification/evaluation-specification.module';
import { EvaluationComposeModule } from '@/module/evaluation-compose/evaluation-compose.module';
import { AudioSynthesisModule } from '@/module/audio-synthesis/audio-synthesis.module';
import { EvaluationFileModule } from '@/module/evaluation-file/evaluation-file.module';
import { TrackModule } from '@/module/track/track.module';
import { XlsxModule } from '@/module/xlsx/xlsx.module';
import { EQModule } from './module/eq/eq.module';
import { RateModule } from './module/rate/rate.module';

@Module({
  imports: [
    ConfigModule.forRoot({
      envFilePath: path.join(
        process.cwd(),
        `config/.env.${process.env.NODE_ENV ?? 'local'}`,
      ),
      isGlobal: true,
    }),
    LoggerModule,
    HttpClientModule,
    ScheduleModule.forRoot(),
    TypeOrmModule.forRootAsync({
      imports: [ConfigModule],
      inject: [ConfigService],
      useFactory: (configService: ConfigService) => {
        return {
          type: 'postgres',
          host: configService.get<string>('PG_HOST'),
          port: configService.get<number>('PG_PORT'),
          username: configService.get<string>('PG_USERNAME'),
          password: configService.get<string>('PG_PASSWORD'),
          logging: Boolean(+(configService.get<string>('PG_LOGGING') ?? 0)),
          entities: getMetadataArgsStorage().tables.map((tbl) => tbl.target),
          uuidExtension: 'pgcrypto',
          maxQueryExecutionTime: 5000,
          database: configService.get<string>('PG_DATABASE'),
          namingStrategy: new SnakeNamingStrategy(),
          synchronize: Boolean(+(configService.get<string>('PG_SYNC') ?? 0)),
        };
      },
      async dataSourceFactory(options) {
        return addTransactionalDataSource(new DataSource(options!));
      },
    }),
    RedisModule.forRootAsync({
      imports: [ConfigModule],
      inject: [ConfigService],
      useFactory: (configService: ConfigService) => {
        const redisConfigs: RedisClientOptions[] = [];
        for (const key in RedisNamespace) {
          redisConfigs.push({
            namespace: RedisNamespace[key as keyof typeof RedisNamespace],
            host: configService.get<string>('REDIS_HOST'),
            port: configService.get<number>('REDIS_PORT'),
            db: configService.get<number>('REDIS_DB'),
            password: configService.get<string>('REDIS_PASSWORD'),
            keyPrefix: `${RedisNamespace[key as keyof typeof RedisNamespace]}:`,
          });
        }
        return { config: redisConfigs };
      },
    }),
    GlobalConfigModule,
    XlsxModule,
    VcodeModule,
    FileModule,
    TrackModule,
    ResourceModule,
    RoleModule,
    AdminModule,
    GlobalConfigModule,
    UserModule,
    CarouselModule,
    BrandModule,
    // CategoryModule,
    ArticleModule,
    SpecificationModule,
    EvaluationProjectModule,
    EvaluationDataModule,
    EvaluationSpecificationModule,
    EvaluationModule,
    EvaluationComposeModule,
    EvaluationFileModule,
    AudioSynthesisModule,
    EQModule,
    RateModule,
  ],
})
export class AppModule {}
